﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Collections;
using System.Threading;
using System.Net;
using NYurik.TimeSeriesDb.Serializers.BlockSerializer;
using NYurik.TimeSeriesDb;
using System.Runtime.InteropServices;
using BNF.HMI.DAL;
using System.Net.Sockets;
using NYurik.TimeSeriesDb.Common;
using DataEngine.DataModel;
using DataEngine.ContractModel;
using BNF.Utility.TimeAPI;
using System.Runtime.CompilerServices;

namespace DataEngine
{
    /// <summary>
    /// ConsoleApplication for DataEngine
    /// Developer: HaiMai
    /// </summary>
    class ConsoleApplication:ServiceLib.IConsole
    {
        private bool isRun = true;
        private Queue<DATA_POINT> MainQueue = new Queue<DATA_POINT>();
        ArchiveDatabase myDatabase = new ArchiveDatabase();

        private Object lockMainQueue = new object();
        private List<H_TLIST> myDBList = new List<H_TLIST>();
        private CTAPI myTimeLib = new CTAPI();
        private TVA.Communication.TcpServer m_server;

        public void Start(bool consoleMode)
        {
            //This is where your console application would be
            ConsoleRun();

            Console.WriteLine("Press Q key to exit...");
            if (consoleMode)
            {
                while (isRun)
                {
                    ConsoleKeyInfo myD = Console.ReadKey();
                    isRun = !(myD.Key == ConsoleKey.Q);
                }
            }
        }
        public void Stop()
        {
            isRun = false;
            // Clear all the things
            DisposeDataServer();
        }

        private void ConsoleRun()
        {
            BNF.HMI.ConfigFile.m_Log.isServer = true;
            // Run all the things
            InitDriverServer();
            InitDataServer();

            
            Thread writeThread = new Thread(new ThreadStart(ProcessDataForStore));
            writeThread.IsBackground = true;
            writeThread.Start();

            //Simulate();
        }
        private void Simulate()
        {
            long StartSimulate = myTimeLib.GetCurrentTimeAsJavaTime(); ;
            while (isRun)
            {
                UInt64 myVal = 1;
                for (int i = 0; i < 3000; i++)
                {
                    DATA_POINT myData = new DATA_POINT();
                    myData.TagID = 542;
                    myData.DataType = 11;
                    myData.Value = BitConverter.GetBytes(myVal);
                    myData.TimeStamp = Convert.ToUInt64((ulong)StartSimulate + (ulong)i);
                    lock (lockMainQueue)
                    {
                        MainQueue.Enqueue(myData);
                    }
                }
                StartSimulate += 3000;

                for (int i = 0; i < 500; i++)
                {
                    DATA_POINT myData = new DATA_POINT();
                    myData.TagID = 2230;
                    myData.DataType = 4;
                    myData.Value = new byte[8];
                    myData.Value[0] = 1;
                    myData.TimeStamp = Convert.ToUInt64((ulong)StartSimulate + (ulong)i);
                    lock (lockMainQueue)
                    {
                        MainQueue.Enqueue(myData);
                    }
                }
                StartSimulate += 500;

                Thread.Sleep(1000);
            }
        }


        #region "DRIVER SERVER"

        private void InitDriverServer()
        {
            string baseListFile = @"C:\BNFTech\TIS\core\Data\BaseTagList.ttl";
            CreateBufferFromFile(baseListFile);
            //LoadDbpoint();

            isRun = true;
            Thread myThread = new Thread(new ThreadStart(ListenDriver));
            myThread.Start();
        }
     
        private bool IsClientConnected(TcpClient tcpClient)
        {
            bool ret = true;
            if (tcpClient.Client.Poll(0, SelectMode.SelectRead))
            {
                byte[] checkConn = new byte[1];
                if (tcpClient.Client.Receive(checkConn, SocketFlags.Peek) == 0)
                {
                    ret = false;
                }
            }
            return ret;
        }
        private void ProcessClient(object ClientSocket)
        {
            byte[] buffer = new byte[5000000];
            TcpClient tcpClient = (TcpClient)ClientSocket;
            tcpClient.NoDelay = true;
            NetworkStream ns = tcpClient.GetStream();
            int TrCount = 0;
            int objCount = 0;
            bool isError = false;
            Console.WriteLine("DriverClient Connected:" + tcpClient.Client.RemoteEndPoint.ToString());
            PACKET_HEADER objHeader;
            DATA_POINT objData;

            while (!isError && isRun)
            {
                try
                {
                    if (!tcpClient.Connected || !IsClientConnected(tcpClient))
                    {
                        isError = true;
                        break;
                    }
                    if (tcpClient.Available > ModelConstants.PACKET_HEADER_SIZE)
                    {
                        //Read Header 
                        ns.Read(buffer, 0, ModelConstants.PACKET_HEADER_SIZE);
                        TrCount++;
                        Console.WriteLine(String.Format("Start reading TrID[{0}]....", TrCount));
                        objHeader = (PACKET_HEADER)clsSocket.Deserialize(buffer, 0, typeof(PACKET_HEADER));
                        if (!CheckHeader(objHeader)) continue;

                        clsSocket.ReadN(ns, buffer, ModelConstants.PACKET_HEADER_SIZE, (int)objHeader.Length);
                        objCount = (int)objHeader.Length / ModelConstants.INSERT_DATA_SIZE;
                        //Parsing Object
                        for (int i = 0; i < objCount; i++)
                        {
                            objData = (DATA_POINT)clsSocket.Deserialize(buffer, i *ModelConstants.INSERT_DATA_SIZE + ModelConstants.PACKET_HEADER_SIZE, typeof(DATA_POINT));
                            //Console.WriteLine(String.Format("TagID [{0}] Timestamp[{1}],Quality [{2}] ", objData.TagID, objData.TimeStamp, objData.Quality));
                            lock (lockMainQueue)
                            {
                                MainQueue.Enqueue(objData);
                            }
                        }

                        Console.WriteLine(String.Format("Completed [{0}] Read [{1}]bytes, [{2}]objects", TrCount, objHeader.Length, objCount));
                    }
                    else
                    {
                        Thread.Sleep(100);
                    }
                }
                catch (Exception)
                {
                    isError = true;
                }
            }

            Console.WriteLine("DriverClient Disconnected:" + tcpClient.Client.RemoteEndPoint.ToString());
            tcpClient.Client.Disconnect(false);
            tcpClient.Close();
        }
        private bool CheckHeader(PACKET_HEADER myHeader)
        {
            bool ret = false;
            if (myHeader.Sign != 0x5A ||
                (
                myHeader.Cmd != (byte)CommandEnum.INSERT_DATA &&
                myHeader.Cmd != (byte)CommandEnum.REQUEST_POINT &&
                myHeader.Cmd != (byte)CommandEnum.REQUEST_LIST &&
                myHeader.Cmd != (byte)CommandEnum.REQUEST_TREND
                ) ||
                myHeader.Length == 0)
            {
                ret = false;
            }
            else
            {
                ret = true;
            }
            return ret;
        }
        private bool CheckHeader(byte[] byteHeader, out uint DataLength)
        {
            PACKET_HEADER myHeader = (PACKET_HEADER)clsSocket.Deserialize(byteHeader, typeof(PACKET_HEADER));
            if (myHeader.Sign != 0x5A ||
                (
                myHeader.Cmd != (byte)CommandEnum.INSERT_DATA &&
                myHeader.Cmd != (byte)CommandEnum.REQUEST_POINT &&
                myHeader.Cmd != (byte)CommandEnum.REQUEST_LIST &&
                myHeader.Cmd != (byte)CommandEnum.REQUEST_TREND
                ) ||
                myHeader.Length == 0)
            {
                DataLength = 0;
                return false;
            }
            else
            {
                DataLength = myHeader.Length;
                return true;
            }
        }
        private void ListenDriver()
        {
            TcpListener tcpipListener = new TcpListener(IPAddress.Any, 9100);
            //============
            while (isRun)
            {
                try
                {
                    tcpipListener.Start();
                    Console.WriteLine("DriverServer has been started!");
                    TcpClient tcpClient = tcpipListener.AcceptTcpClient();
                    Thread myThread = new Thread(ProcessClient);
                    myThread.Name = "ProcessClientThread";
                    myThread.Start(tcpClient);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error when listening");
                }
            }
        }

        #endregion

        #region "ARCHIVE SERVER"
        // Key: TagID, Value: QUeue of LEX_DATA
        private Hashtable DataMap = new Hashtable();
        private void ProcessDataForStore()
        {
            int ProcessStep = 0;
            while (isRun)
            {
                if (MainQueue.Count > 0)
                {
                    myDatabase.ProcessDB();
                    ProcessStep += DistributeData(MainQueue);
                    if (ProcessStep > 0)
                    {
                        Console.WriteLine(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff") + " START Writing [" + ProcessStep.ToString() + "] to DB QueueCount:" + MainQueue.Count.ToString());
                        int Count = 0;
                        foreach (DictionaryEntry it in DataMap)
                        {
                            Count++;
                            //Console.WriteLine("Processing:"+Count.ToString());
                            myDatabase.Write2DB((uint)it.Key, (Queue<DATA_POINT>)it.Value);
                        }
                        Console.WriteLine(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff") + " FINISH Writing to DB");
                        ProcessStep = 0;
                    }
                }
                else
                {
                    Thread.Sleep(100);
                }
            }

        }
        // Load from BaseTagList.ttl & InitMap
        private void CreateBufferFromFile(string fileName)
        {
            try
            {

                using (BinaryReader b = new BinaryReader(File.Open(fileName, FileMode.Open, FileAccess.Read)))
                {

                    int pos = 0;
                    // 2A.
                    // Use BaseStream.
                    int length = (int)b.BaseStream.Length;
                    byte[] myLine;

                    if (!File.Exists(fileName))
                    {
                        return;
                    }

                    H_TLIST myObj;
                    //If server's writing was not done, then ignore
                    int ObjCount = length / ModelConstants.H_TLIST_SIZE;
                    int IgnoredByte = length - ObjCount * ModelConstants.H_TLIST_SIZE;
                    if (IgnoredByte > 0)
                    {
                        Console.WriteLine("Ignored ==>{0} bytes", IgnoredByte);
                    }

                    length = ObjCount * ModelConstants.H_TLIST_SIZE;
                    while (pos < length)
                    {

                        myLine = b.ReadBytes(ModelConstants.H_TLIST_SIZE);
                        if (myLine.Length < ModelConstants.H_TLIST_SIZE)
                        {
                            Console.WriteLine("ERROR-----------------------------");
                        }
                        myObj = (H_TLIST)clsSocket.Deserialize(myLine, typeof(H_TLIST));
                        if (!DataMap.Contains(myObj.TagID))
                        {
                            Queue<DATA_POINT> myTagQueue = new Queue<DATA_POINT>();
                            DataMap.Add(myObj.TagID, myTagQueue);
                            myDBList.Add(myObj);
                            myDatabase.SetDataType(myObj.TagID, myObj.DataType);
                            BNF.HMI.ConfigFile.m_Log.AddLog(String.Format("TagID:{0} DataType:{1}", myObj.TagID, myObj.DataType));
                        }

                        pos += ModelConstants.H_TLIST_SIZE;

                    }

                    b.Close();
                }


                Console.WriteLine(String.Format("================>Loaded [{0}] Tags", DataMap.Count));
                GC.Collect();
            }
            catch (System.Exception ex)
            {
                Console.WriteLine("LoadTagListFromFile ERROR: " + ex.ToString());
            }

        }
        private void LoadDbpoint()
        {
            clsDatabase myDB = new clsDatabase();
            String strcon = clsDatabase.fncGetConnectionString("127.0.0.1", "TIS", "tisuser", "123456");
            string strcmd = String.Empty;
            //============== Create table if it doesn't exist
            //strcmd = " CREATE TABLE `logicdbpoint` ( ";
            //strcmd += " `TagID` int(10) NOT NULL, ";
            //strcmd += " `TagName` varchar(255) COLLATE utf8_bin NOT NULL, ";
            //strcmd += " `DataType` smallint(5) unsigned NOT NULL, ";
            //strcmd += " PRIMARY KEY (`TagID`) ";
            //strcmd += " ) ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_bin; ";
            //myDB.fcnExecNonQuery(strcon, strcmd);
            strcmd = "truncate table logicdbpoint; ";
            myDB.fcnExecNonQuery(strcon, strcmd);

            foreach (H_TLIST item in myDBList)
            {
                strcmd = String.Format(" Insert into logicdbpoint values ({0},'{1}',{2}); ", item.TagID, item.TagName, item.DataType);
                myDB.fcnExecNonQuery(strcon, strcmd);
            }
        }


        // From MainQueue to ItemQueue
        private int DistributeData(Queue<DATA_POINT> MainQueue)
        {

            int currentCount = MainQueue.Count;
            int ProcessStep = (currentCount > 50000) ? 50000 : currentCount;

            DATA_POINT myObj = new DATA_POINT();
            for (int i = 0; i < ProcessStep; i++)
            {
                lock (lockMainQueue)
                {
                    myObj = MainQueue.Dequeue();
                }
                if (DataMap.ContainsKey(myObj.TagID))
                    ((Queue<DATA_POINT>)DataMap[myObj.TagID]).Enqueue(myObj);
                else
                {
                    Console.WriteLine("Cannot find tagid[{0}]",myObj.TagID);
                }
            }

            return ProcessStep;
        }
        #endregion

        #region "DATA SERVER"

        private void InitDataServer()
        {
            myDatabase.Init();
            // Initialize the server.
            m_server = new TVA.Communication.TcpServer("Port=9101");
            m_server.Handshake = false;
            m_server.PayloadAware = false;
            m_server.ReceiveTimeout = -1;
            m_server.Encryption = TVA.Security.Cryptography.CipherStrength.None;
            m_server.Compression = TVA.IO.Compression.CompressionStrength.NoCompression;
            m_server.SecureSession = false;
            m_server.Initialize();
            // Register event handlers.
            m_server.ServerStarted += m_server_ServerStarted;
            m_server.ServerStopped += m_server_ServerStopped;
            m_server.ClientConnected += m_server_ClientConnected;
            m_server.ClientDisconnected += m_server_ClientDisconnected;
            m_server.ReceiveClientDataComplete += m_server_ReceiveClientDataComplete;
            // Start the server.
            m_server.Start();   
        }
        private void DisposeDataServer()
        {
            // Stop the server on shutdown.
            m_server.Stop();
        }
   
        private RequestType GetDataType(REQUEST_HEADER p_RequestHeader)
        {
            RequestType ret = RequestType.PointData;
            if (p_RequestHeader.resolution != 0 && p_RequestHeader.duration != 0 && p_RequestHeader.endtime != 0)
            {
                ret = RequestType.TrendData;
            }
            else if (p_RequestHeader.duration != 0 && p_RequestHeader.endtime != 0)
            {
                ret = RequestType.ListData;
            }
            else
            {
                ret = RequestType.PointData;
            }

            return ret;
        }
        private MemoryStream  ProcessClientRequest(byte[] InBuffer)
        {
            MemoryStream OutBuffer = new MemoryStream();
            // ============Process Header
            PACKET_HEADER myHeader = (PACKET_HEADER)clsSocket.Deserialize(InBuffer, 0, typeof(PACKET_HEADER));
            REQUEST_HEADER myRequest = (REQUEST_HEADER)clsSocket.Deserialize(InBuffer, ModelConstants.PACKET_HEADER_SIZE, typeof(REQUEST_HEADER));

            uint TagCount = (uint)(myHeader.Length - ModelConstants.REQUEST_HEADER_SIZE) / sizeof(UInt32);

            List<Object> myTagList= clsSocket.Deserialize(InBuffer, ModelConstants.PACKET_HEADER_SIZE + ModelConstants.REQUEST_HEADER_SIZE, typeof(uint), (int)TagCount);
            List<Object> myRet = myDatabase.GetData(myTagList, myRequest);
            // Process Header for Sending
            myHeader.Cmd = (byte)CommandEnum.RESPONSE_POINT;
            myHeader.Length = (uint)(myRet.Count * ModelConstants.INSERT_DATA_SIZE);

            clsSocket.Serialize(OutBuffer,myHeader,myRet);

            return OutBuffer;
        }

        private void m_server_ServerStarted(object sender, EventArgs e)
        {
            Console.WriteLine("DataServer has been started!");
        }
        private void m_server_ServerStopped(object sender, EventArgs e)
        {
            Console.WriteLine("DataServer has been stopped!");
        }
        private void m_server_ClientConnected(object sender, TVA.EventArgs<Guid> e)
        {
            Console.WriteLine(string.Format("DataClient Connected:{0}", m_server.Client(e.Argument).Provider.LocalEndPoint));
        }
        private void m_server_ClientDisconnected(object sender, TVA.EventArgs<Guid> e)
        {
            try
            {
                Console.WriteLine(string.Format("DataClient Disconnected:{0}", e.Argument));
            }
            catch (Exception ex)
            {
                string t = ex.ToString();
            }
            
        }
        private void m_server_ReceiveClientDataComplete(object sender, TVA.EventArgs<Guid, byte[], int> e)
        {

            int processCount=0;
            int remain=0;

            //Console.WriteLine(string.Format("Received data from {0} - {1}.", e.Argument1, m_server.TextEncoding.GetString(e.Argument2, 0, e.Argument3)));
            Console.WriteLine(string.Format("Received data from {0} - {1}.", m_server.Client(e.Argument1).Provider.LocalEndPoint, e.Argument3));
            processCount = e.Argument3;

            byte[] InBuffer = new byte[10000];
            NetworkStream ns = new NetworkStream(m_server.Client(e.Argument1).Provider);

            // Copy all data
            Buffer.BlockCopy(e.Argument2, 0, InBuffer, 0, e.Argument3);

            // Get completely header
            if (processCount <= ModelConstants.PACKET_HEADER_SIZE)
            {
                // Get header if needed
                remain = ModelConstants.PACKET_HEADER_SIZE - processCount;
                if (remain > 0) clsSocket.ReadN(ns, InBuffer, 0, remain);
            }
            

            // Get completely data
            PACKET_HEADER myHeader = (PACKET_HEADER)clsSocket.Deserialize(InBuffer, 0, typeof(PACKET_HEADER));
            
            remain= (processCount <= ModelConstants.PACKET_HEADER_SIZE)? (int)(myHeader.Length):(int)(myHeader.Length - processCount);
            if (remain > 0) clsSocket.ReadN(ns, InBuffer, e.Argument3, remain);

            Console.WriteLine(string.Format(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff") +"  Received COMPLETELY {0} bytes", myHeader.Length + ModelConstants.PACKET_HEADER_SIZE));
            MemoryStream OutBuffer= ProcessClientRequest(InBuffer);

            if (ns.CanWrite)
            {
                try
                {
                    OutBuffer.WriteTo(ns);
                    Console.WriteLine(string.Format(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff") +"  Sent COMPLETELY {0} bytes", OutBuffer.Length));
                }
                catch (Exception)
                {
                    Console.WriteLine(string.Format("Cannot send to client {0} bytes", OutBuffer.Length));
                }
            }
            else
            {
                Console.WriteLine(string.Format("Cannot send to client {0} bytes", OutBuffer.Length));
            }
            

        }
        #region OLD_CODE
        //private void m_server_ReceiveClientDataComplete(object sender, TVA.EventArgs<Guid, byte[], int> e)
        //{
        //    int ProcessDoneByteCount = 0;
        //    while (ProcessDoneByteCount < e.Argument3)
        //    {

        //        //Console.WriteLine(string.Format("Received data from {0} - {1}.", e.Argument1, m_server.TextEncoding.GetString(e.Argument2, 0, e.Argument3)));
        //        Console.WriteLine(string.Format("Received data from {0} - {1}.", e.Argument1, e.Argument3));
        //        Console.WriteLine("ID =" + Count.ToString());
        //        byte[] byteHeader = new byte[8];
        //        int remain = (e.Argument3 - ProcessDoneByteCount) - byteHeader.Length;
        //        int invertRemain = 0;
        //        uint DataLength = 0;
        //        NetworkStream ns = new NetworkStream(m_server.Client(e.Argument1).Provider);
        //        List<uint> myTagIDList = new List<uint>();
        //        // Not enough data, so read more
        //        if (remain <= 0)
        //        {
        //            invertRemain = remain * (-1);
        //            Buffer.BlockCopy(e.Argument2, ProcessDoneByteCount, byteHeader, 0, (e.Argument3 - ProcessDoneByteCount));
        //            if (remain < 0)
        //            {
        //                Console.WriteLine(string.Format("Not enough data header case"));
        //                int test = ns.Read(byteHeader, (e.Argument3 - ProcessDoneByteCount), invertRemain);
        //                if (test != invertRemain)
        //                {
        //                    ;
        //                }

        //            }
        //            else
        //            {
        //                Console.WriteLine(string.Format("Fit data header case"));
        //            }
        //            ProcessDoneByteCount += byteHeader.Length;

        //            if (CheckHeader(byteHeader, out DataLength))
        //            {
        //                byte[] byteData = new byte[DataLength];
        //                byte[] byteDataItem = new byte[ModelConstants.TAG_ID_SIZE];

        //                int test = ns.Read(byteData, 0, (int)DataLength);
        //                // Implement readN in here
        //                if (test != invertRemain)
        //                {
        //                    ;
        //                }
        //                ProcessDoneByteCount += (int)DataLength;

        //                long ItemCount = DataLength / ModelConstants.TAG_ID_SIZE;
        //                Console.WriteLine(string.Format("Received data Count {0}.", ItemCount));
        //                for (int i = 0; i < ItemCount; i++)
        //                {
        //                    //Buffer.BlockCopy(byteData, (int)(i * ModelConstants.TAG_ID_SIZE), byteDataItem, 0, ModelConstants.TAG_ID_SIZE);
        //                    myTagIDList.Add(BitConverter.ToUInt32(byteData, (int)(i * ModelConstants.TAG_ID_SIZE)));
        //                }

        //                Console.WriteLine(string.Format("Data Count {0}.", myTagIDList.Count));
        //            }
        //            else
        //            {
        //                ProcessDoneByteCount = e.Argument3;
        //                Console.WriteLine("Error Header");
        //            }
        //        }
        //        else
        //        {
        //            Console.WriteLine(string.Format("More enough data header case"));
        //            // Enough Data, so process
        //            Buffer.BlockCopy(e.Argument2, ProcessDoneByteCount, byteHeader, 0, byteHeader.Length);
        //            ProcessDoneByteCount += byteHeader.Length;

        //            if (CheckHeader(byteHeader, out DataLength))
        //            {
        //                byte[] byteData = new byte[DataLength];

        //                if (e.Argument3 - ProcessDoneByteCount >= DataLength)
        //                {
        //                    // More data than data header, so read only the less
        //                    Buffer.BlockCopy(e.Argument2, ProcessDoneByteCount, byteData, 0, (int)DataLength);
        //                }
        //                else
        //                {
        //                    // More data than data header, so read only the less
        //                    Buffer.BlockCopy(e.Argument2, ProcessDoneByteCount, byteData, 0, invertRemain);
        //                    // Read More from Stream
        //                    ns.Read(byteData, invertRemain, (int)DataLength - invertRemain);
        //                }

        //                ProcessDoneByteCount += (int)DataLength;
        //                Console.WriteLine(string.Format("Received data Count {0}.", ProcessDoneByteCount));                       
        //                byte[] OutBuffer= new byte[30000];
        //                ProcessClientRequest(e.Argument2, OutBuffer);
        //            }
        //            else
        //            {
        //                ProcessDoneByteCount = e.Argument3;
        //                Console.WriteLine("Error Header");
        //            }
        //        }

        //    }

        //    Console.WriteLine("Complete Processing");
        //}
        #endregion
      
       
        #endregion
    }

    public static class RuntimePolicyHelper
    {
        public static bool LegacyV2RuntimeEnabledSuccessfully { get; private set; }

        static RuntimePolicyHelper()
        {
            ICLRRuntimeInfo clrRuntimeInfo =
                (ICLRRuntimeInfo)RuntimeEnvironment.GetRuntimeInterfaceAsObject(
                    Guid.Empty,
                    typeof(ICLRRuntimeInfo).GUID);
            try
            {
                clrRuntimeInfo.BindAsLegacyV2Runtime();
                LegacyV2RuntimeEnabledSuccessfully = true;
            }
            catch (COMException)
            {
                // This occurs with an HRESULT meaning 
                // "A different runtime was already bound to the legacy CLR version 2 activation policy."
                LegacyV2RuntimeEnabledSuccessfully = false;
            }
        }

        [ComImport]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        [Guid("BD39D1D2-BA2F-486A-89B0-B4B0CB466891")]
        private interface ICLRRuntimeInfo
        {
            void xGetVersionString();
            void xGetRuntimeDirectory();
            void xIsLoaded();
            void xIsLoadable();
            void xLoadErrorString();
            void xLoadLibrary();
            void xGetProcAddress();
            void xGetInterface();
            void xSetDefaultStartupFlags();
            void xGetDefaultStartupFlags();

            [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
            void BindAsLegacyV2Runtime();
        }
    }
}
